package main

import (
	"fmt"
	"time"
)

/**
 * 协程 类似多线程，但执行速度更快，因为协程是并发执行。
 */
// 定义一个函数，作为协程执行的任务
func sayHello() {
	for i := 0; i < 5; i++ {
		fmt.Println("Hello")
		time.Sleep(500 * time.Millisecond) // 模拟耗时操作
	}
}

func 关闭channel() {
	c := make(chan int)
	go func() {
		for i := 0; i < 3; i++ {
			c <- i
		}
		close(c) // 关闭channel
	}()

	//方式一
	/*for {
		if data, ok := <-c; ok {
			fmt.Println("data:", data)
		} else {
			break
		}
	}*/
	//方式二
	for data := range c {
		fmt.Println("data:", data)
	}
}

func selectChannel() {
	c := make(chan int)
	q := make(chan int)

	go func() {
		for i := 0; i < 5; i++ {
			c <- i
			time.Sleep(500 * time.Millisecond)
		}

		q <- 0
		fmt.Println("q=0 结束")
	}()

	for {
		select {
		case data := <-c:
			fmt.Println("data:", data)
		case data := <-q:
			fmt.Println("data:", data)
			return
		}
	}
}

func main() {
	// 启动一个协程执行 sayHello 函数
	go sayHello()

	// 主协程继续执行其他操作
	for i := 0; i < 3; i++ {
		fmt.Println("Main")
		time.Sleep(100 * time.Millisecond) // 模拟耗时操作
	}

	// 等待一段时间，确保协程执行完毕
	fmt.Println("-----------------------------------")

	// 定义一个无缓冲的通道
	c := make(chan int)
	go func() {
		defer fmt.Println("goroutine end.... \n")

		//给通道c发送一个值
		c <- 1 // 发送数据，当协程接收到数据时，会继续往下执行
		fmt.Printf("date: %s  \n", time.Now())
	}()

	time.Sleep(2 * time.Second)
	//读取通道c
	num := <-c // 当num没有获取到数据时，会阻塞，等待数据
	fmt.Println("num:", num)
	fmt.Printf("date1: %s  \n", time.Now())
	fmt.Println("-----------------------------------")

	//定义一个有缓冲的通道
	n := make(chan int, 3)

	go func() {
		defer fmt.Println("goroutine end.... \n")

		for i := 0; i < 5; i++ {
			n <- i
			fmt.Println("向n发送数据", i, " len: ", len(n), " cap:", cap(n))
			time.Sleep(300 * time.Millisecond)
		}

	}()

	time.Sleep(2 * time.Second) //保证协程执行完毕

	for i := 0; i < 5; i++ {
		num := <-n
		fmt.Println("接收n的数据", num, "len:", len(n))
	}
	fmt.Println("-----------------------------------")
	关闭channel()
	fmt.Println("-----------------------------------")
	selectChannel()
}
